(** Module SimplifyGrammar contains:
 *  - functions for grammar simplification 
 *    (Elkhoud does not allow grammar such this:
 *
 *      a ( b | c ) d     (1)
 *
 *     that's why we convert (1) to:
 *
 *      a yard_alt_1 d 
 *
 *     and generate definition for rule yard_alt_1:
 *
 *      yard_alt_1 { -> b; -> c; } 
 *    )
 *
 *  Author: Ilia
 *)

open IL
open Misc.Generation
open Production
open Namer
open TransformAux


let rec simplifyBody rules params = function
    | PAlt (l, r) ->
      let (rs', l') = simplifyBody rules params l 
      in let (rs'', r') = simplifyBody rs' params r 
      in (rs'', PAlt (l', r'))
    | PSeq (seq, a) -> 
      let rec simplifyItem rules params' = function
          | PAlt (_, _) as b -> 
            let newName = createNewName (createSource Names.alt) in
            let strName = getText newName in
            let rule = createSimpleRule strName params' b in
            let (rs, b') = simplifyBody rules params' b 
            in ( rs @ [{rule with Rule.body = b'}]
               , createRef strName (createOpt params')
               )
          | other -> (rules, other)

      in let rec simplifySeq rs paramList = function
             | [] -> (rs, [])
             | h::t -> let params' = createParams paramList in
               let (rs', b') = simplifyItem rs params' h.rule in
               let paramList' = addBinding paramList h.binding in
               let (rs'', l') = simplifySeq rs' paramList' t
             in (rs'', { h with rule = b' } :: l')

      in let (rs', seq') = simplifySeq rules params seq
      in (rs', PSeq (seq', a))
    | other -> (rules, other)

let simplifyRule r =
    let (rules, b) = simplifyBody [] r.Rule.args r.Rule.body 
    in rules @ [{ r with Rule.body = b }]

(** main function *)
let rec simplifyRules rules =
    match rules with
    | [] -> []
    | h::t -> 
      let l' = simplifyRule h in l' @ simplifyRules t

(* end of grammar simplification (for Elkhoud) *)
